import { showConsole, baseUrl, env } from "../config/index.js";
import * as $utils from "./utils.js";
import store from "../store/index.js";

let mockData = null;

const defaultOpts = {
  timeout: 30000,
  showLoading: "加载中", // 默认所有接口展示Loading
  showError: true, // 默认所有接口报错的话展示弹框
  errorTips: "系统繁忙，请稍后再试", // 默认所有接口报错的话展示弹框
  header: {
    "Content-Type": "application/json",
  },
  // withCredentials: true,
};

// 定义成功code数组
const successCode = ["0", "1", "200"];

/**
 * 判断url是否为绝对路径
 * @param {string} url
 * @returns {boolean}
 * */
function posUrl(url) {
  return /(http|https):\/\/([\w.]+\/?)\S*/.test(url);
}

function handleError(opts, response, reject) {
  if (opts.showLoading) {
    $utils.loading(null);
  }
  if (String(response.errorCode) === "#401") {
    uni.showToast({
      title: response.errorMsg || "登录失效，请重新登录",
      icon: "none",
      duration: 1500,
    });
    setTimeout(() => {
      store.commit("user/clearToken");
      uni.reLaunch({
        url: "/pages/account/loginSelect",
      });
    }, 1500);
    return;
  }
  if (opts.showError) {
    $utils.modal({
      content:
        response.errorMsg ||
        response.msg ||
        response.errmsg ||
        response.message ||
        opts.errorTips,
    });
  }
  // 输出表格报错信息
  try {
    const json = {
      url: opts.url,
      method: opts.method.toUpperCase(),
      code:
        response.returnCode ||
        response.code ||
        response.errcode ||
        response.status ||
        response.statusCode,
      message:
        response.errorMsg ||
        response.msg ||
        response.errmsg ||
        response.message,
      timeout: response.timeout,
      header: JSON.stringify(opts.header),
      data: JSON.stringify(opts.data),
      "Content-Type": opts.header["Content-Type"],
      "response JSON": JSON.stringify(response),
    };
    console.table(json);
  } catch (error) {
    console.log("error: ", error);
  }

  reject && reject(response);
}

// 对请求数据进行处理
function formatRequest(opts) {
  // 深拷贝opts
  let config = JSON.parse(JSON.stringify(opts));

  if (!config.header) {
    config.header = {};
  }

  if (config.method.toLowerCase() === "post") {
    if (!config.header["Content-Type"]) {
      // config.header["Content-Type"] = "application/x-www-form-urlencoded";
      config.header["Content-Type"] = "application/json";
    }
  }
  config.header = {
    ...defaultOpts.header,
    ...config.header,
  };

  const data = config.data || {};

  // 为了避免get请求有缓存，在url后加上时间戳
  if (config.method.toLowerCase() === "get") {
    data.t = new Date().getTime();
  }

  // 合并opts与defaultOpts
  config = {
    ...defaultOpts,
    ...config,
    method: config.method || "get",
    originUrl: config.url,
    url: posUrl(config.url) ? config.url : baseUrl + config.url,
    data: data,
  };
  // 如果存在token，则每个http header都加上token
  const token = uni.getStorageSync("token");
  if (token) {
    // config.header["Authorization"] = "Bearer " + token;
    config.header["token"] = token;
  }

  if (config.showLoading) {
    $utils.loading(config.showLoading, true);
  }
  return config;
}

function formatResponse(opts, res, resolve, reject) {
  if (!!res.data.success) {
    if (opts.showLoading) {
      $utils.loading(null);
    }
    resolve(res.data);
  } else {
    handleError(opts, res.data, reject);
  }
}

const httpRequest = (opts) => {
  return new Promise(function (resolve, reject) {
    const config = formatRequest(opts);
    // #ifdef APP
    if (env === "mock") {
      /* APP无法使用MOCK服务器*/
      if (config.showLoading) {
        $utils.loading(config.showLoading);
      }
      if (!mockData) {
        const files = require.context("../api-mock/modules", false, /\.js$/);
        files.keys().forEach((key) => {
          mockData = mockData || {};
          Object.assign(
            mockData,
            require("../api-mock/modules" + key.slice(1))
          );
        });
      }
      setTimeout(() => {
        if (mockData[config.originUrl]) {
          if (!!config.showLoading) {
            $utils.loading(null);
          }
          const res = mockData[config.originUrl]() || {};
          showConsole &&
            console.log(`请求地址: ${config.url}`, `返回对象: `, res);
          resolve(res);
        } else {
          reject("未找到mock方法" + config.url);
        }
      }, 800);
      return;
    }
    // #endif
    uni.request({
      ...config,
      success(res) {
        formatResponse(config, res, resolve, reject);
      },
      fail(error) {
        handleError(config, error, reject);
      },
    });
  });
};

httpRequest.upload = (config) => {
  return new Promise((resolve) => {
    $utils.loading("上传中...");
    uni.uploadFile({
      url: posUrl(config.url) ? config.url : baseUrl + config.url, //仅为示例，非真实的接口地址
      filePath: config.data.filePath,
      name: "file",
      formData: {
        ...config.data.formData,
      },
      success: (uploadFileRes) => {
        resolve(JSON.parse(uploadFileRes.data));
      },
      complete: (uploadFileRes) => {
        $utils.loading(null);
      },
    });
  });
};

export default httpRequest;
